javascript 在創建執行環境時做的其中兩件事是做創造和提升
先來看看示範:
// app.js
var a = 'Hello world!'
function b () {
console.log('call b!')
}
b()
console.log(a)
在 console 會出現
// console
call b!
Hello world!
那將執行的程式碼移到宣告前面會怎麼樣?
// app.js
b()
console.log(a)
var a = 'Hello world!'
function b () {
console.log('call b!')
}
// console
call b!
undefined
可以看到沒有出現錯誤,函數一樣被執行,而變數變成 undefind
,這是 javascript 特有的現象,稱為 hoisting
首先,執行環境被分為兩階段
第一階段是創造跟提升
執行環境「創造」了全域物件、this 和外部環境,還有「提升」,主要就是「設定變數和函數到記憶體裡」
設定變數時,都會給它 undefind 當作初始值,就像是 placeholder 一樣,換成中文就是「未被宣告的」
所以以前面的例子來說,變數 a 跟函數 b 都會存進記憶體
// 記憶體
a = undefind
function b () {
console.log('call b!')
}
這是第一階段,那第二階段呢?就是開始執行程式碼,一行一行的按照順序執行,用上面的例子稍微修改一下:
// app.js
b()
console.log(a)
var a = 'Hello world!'
console.log(a)
function b () {
console.log('call b!')
}
從第一行 b()
開始,這邊編譯器就會發現需要 b 這個函數,於是到記憶體找一找,發現真的有存這個函數,於是執行函數
第二行發現需要 a 這個變數,於是到記憶體找一找,發現有 a 這個變數,值為 undefind,於是 console.log 出來為 undefind
第三行發現了等號,把記憶體中 a 的值改為 Hello world!
第四行又需要 a 變數,再找一下記憶體,發現有 a 且此時的值為 Hello world!,於是印出 Hello world!
故事大概是醬子。
首先比較一下,有使用 var
宣告 a 跟沒有的情況
有使用 var
宣告:
// app.js
var a
console.log(a)
// console
undefind
沒有宣告:
// app.js
console.log(a)
// console
> Uncaught ReferenceError: a is not defined
可以看到一個是 undefind
一個是 not defined
對變數來說,undefind
和 not defined
是不同的
Uncaught ReferenceError: a is not defined
仔細看這個錯誤,他的意思是「無法參照的錯誤」,因為在創造階段時,沒有設定 a 到記憶體中,所以執行的時候他找不到。
undefind 是一個特殊關鍵字,是變數在創造階段被設定的值
不要將變數設為 undefind,這會增加 debug 的困難,最好讓 undefind 就表示為你從沒宣告過的值。
總結